================================================================================
TEPS REGISTRATION CORE — CODEBASE ONBOARDING
================================================================================

Contributors: Mikal Farley
Created:      April 2026
Last Updated: April 11, 2026

================================================================================
1. WHAT IS THIS APP?
================================================================================

TEPS Registration Core is a macOS menu-bar application that runs a local HTTP
server to manage customer registration and queue flow for photography events.

Think of it as the brain behind a multi-station photo experience. Customers
arrive, register (walk-in or reservation), move through a series of stations
(host, elf, camera, preview, checkout), and leave with their photos. This app
orchestrates the entire flow.

The app runs headless in the menu bar with a colored status indicator (green =
running, orange = needs setup, red = stopped). A full dashboard window is
available for operators to monitor registrations, manage queues, and configure
the system.


================================================================================
2. THE MISSION
================================================================================

Replace the legacy PHP/Bamboo queue management system with a native macOS app
that:

  - Works offline (no internet required for core functionality)
  - Runs a local HTTP server that station devices (iPads, browsers) connect to
  - Serves responsive HTML station pages — zero client installation
  - Optionally syncs with a cloud server for multi-device and reservation data
  - Handles licensing, credential management, and photo code assignment
  - Is configurable enough for Santa events, pet photos, portrait studios, and
    haunted house experiences — all from the same binary


================================================================================
3. HOW IT WORKS — THE BIG PICTURE
================================================================================

                         +---------------------------+
                         |   TEPS Registration Core  |
                         |     (macOS menu bar)      |
                         |                           |
                         |  SQLite DB    HTTP Server  |
                         |  (actor)      (NWListener) |
                         +---------------------------+
                                    |
                         Port 8585 (configurable)
                                    |
              +----------+----------+----------+----------+
              |          |          |          |          |
           iPad 1     iPad 2     iPad 3     Browser    Browser
           (Host)     (Camera)   (Preview)  (Overview) (POS)

  1. The app starts, checks its license, and creates or loads an event.
  2. It boots an HTTP server on the local network (default port 8585).
  3. Station devices open browser pages served by the app.
  4. All data lives in a local SQLite database.
  5. Optionally, a cloud sync service pushes/pulls to the admin server.


================================================================================
4. STARTUP SEQUENCE
================================================================================

  AppController.applicationDidFinishLaunching()
    |
    +-- LogService.initialize()
    +-- DatabaseService() — opens SQLite, runs migrations
    +-- LicenseService.checkLicense()
    |     |
    |     +-- Valid? -> proceedAfterLicense()
    |     +-- Invalid? -> Show LicenseView (app is gated)
    |
    +-- proceedAfterLicense()
          |
          +-- CredentialService.start() — scan Desktop for XML credential files
          +-- Check for active event
          |     |
          |     +-- No event? -> Show SetupView
          |     +-- Has event? -> startServices()
          |
          +-- startServices()
                |
                +-- HTTPServer.start() (with keep-alive auto-restart)
                +-- HeartbeatService.start() (15-min POST to admin server)
                +-- LateMarkingService.start() (marks late reservations)
                +-- SyncService.start() (cloud sync + local schedule)


================================================================================
5. STATION WORKFLOW
================================================================================

The customer journey through the stations:

  Host (check-in) --> [Elf (optional)] --> Camera --> Preview --> Checkout --> Complete

Each station has a two-phase queue:
  - "Waiting" — customer has been sent to this station (via "Next")
  - "Active" — operator clicked "Start" to begin working with them

Queue log tracks three actions per station:
  - "entered"  — customer arrived at the station queue
  - "started"  — operator activated them
  - "exited"   — customer left the station (advanced to next)


================================================================================
6. HTML STATION PAGES (BROWSER ENDPOINTS)
================================================================================

These are full HTML+CSS+JS pages served by the app. Station devices (iPads,
laptops, any browser) navigate to these URLs on the local network.

  /hoststation       Host (Check-In) Station
                     The front desk. Operators search reservations, register
                     walk-ins, and send customers into the workflow.

  /elfstation        Elf Station (optional)
                     A helper station between host and camera. Collects child
                     names, wishlists, elf assignments. Enabled via config.

  /camerastation     Camera Station
                     The photographer's view. Shows the current customer's info,
                     photo code, and party details. Can optionally include the
                     full host check-in panel for single-operator setups
                     (combineHostAndCapture config).

  /santa             Santa Display
                     Read-only display showing the current customer at camera/
                     host. Used so Santa (or the subject) can see who's coming.

  /previewstation    Preview Station
                     Where customers review their photos. Shows order info and
                     package selections.

  /posstation        POS (Point of Sale) Station
                     Checkout. Package selection, order totals, promo codes.
                     Can be combined with Preview (combinePreviewAndPOS config).

  /overview          Overview Dashboard
                     A live summary of all station queues. Shows total
                     registered, checked in, waiting, and in-progress counts.
                     No customer interaction — just a status board.

  /registration      Customer Self-Registration Form
  /tepsregistration  (Same page, alternate URL)
                     A public-facing form for customers to register themselves.
                     Dynamic fields driven by /api/config/fields. Supports
                     multi-child registration, opt-ins, custom fields, and
                     walk-in profile wizard flows.

  /changecode        Code Change Utility
                     Admin tool for reassigning or swapping photo codes between
                     registrations. Used when a sitting folder needs to move.


================================================================================
7. JSON API ENDPOINTS
================================================================================

The app exposes a REST-style JSON API. This is the contract that all station
pages and future clients (Flutter app) consume.

  STATUS & CONFIG
    GET  /api/status              Server health, event info, counts
    GET  /api/event               Active event details
    POST /api/events              Create a new event
    GET  /api/config/fields       Registration form field configuration
    GET  /api/config/statuses     Status string -> display name map
    POST /api/validate/email      Server-authoritative email validation
    GET  /api/schedule            Today's time slots and reservations

  REGISTRATION CRUD
    GET  /api/registrations       List (filters: status, station, code, date)
    POST /api/registrations       Create a new registration
    GET  /api/registrations/{id}  Get one registration
    PUT  /api/registrations/{id}  Update fields on a registration
    GET  /api/registrations/code/{code}  Lookup by photo code

  WORKFLOW
    POST /api/registrations/{id}/checkin   Move to checked-in
    POST /api/registrations/{id}/start     Activate at current station
    POST /api/registrations/{id}/advance   Move to next station
    POST /api/registrations/{id}/return    Send back to previous station
    POST /api/registrations/{id}/cancel    Cancel registration

  QUEUE & OVERVIEW
    GET  /api/queue/{station_type}          Queue for a specific station
    GET  /api/queue/{station_type}/current  Currently active customer
    GET  /api/overview                      Aggregate station counts

  ORDERS
    POST /api/registrations/{id}/order   Create order for registration
    GET  /api/registrations/{id}/order   Get order
    POST /api/orders/{id}/status         Update order status
    POST /api/orders/{id}/packages       Add package to order
    GET  /api/orders/{id}/packages       List packages on order

  UPLOADS & CODE CHANGE
    POST /api/registrations/{id}/userdata  Upload customer data to cloud
    POST /api/code/reassign                Reassign photo code
    POST /api/code/swap                    Swap two codes
    GET  /api/code/files/{code}            List files for a code

  THEME
    GET  /api/theme/css                    CSS variables for active theme
    GET  /api/theme/background             Custom background image
    GET  /api/theme/logo                   Custom logo image

  TESTING
    POST /api/test                         Create a test registration
    POST /api/test/cleanup                 Delete all test registrations


================================================================================
8. ARCHITECTURE PRINCIPLES
================================================================================

  API-FIRST
    The server is the brain, clients are just screens. All business logic
    (status transitions, email validation, phone normalization, notes parsing,
    code generation) lives server-side. Station HTML pages consume the API
    without duplicating logic. This is intentional — a future Flutter mobile
    client will use the same API.

  ACTOR-BASED DATABASE
    DatabaseService is a Swift actor. All database access is serialized
    through the actor's mailbox. The SQLite C API is used directly (no ORM,
    no SwiftData, no CoreData). Column migrations run on startup so older
    databases automatically gain new fields.

  ENRICHED RESPONSES
    Registration JSON includes computed fields (status_display,
    structured_notes, is_queue_active) that the server calculates so clients
    don't need to. This is set in readRegistration() and createRegistration().

  THEME SYSTEM
    14 curated themes with light + dark palettes. All HTML templates use CSS
    variables (--theme-bg, --theme-text, --theme-accent, etc). Themes are
    selectable in Settings. Custom background and logo images supported.

  CONFIGURATION VIA USERDEFAULTS
    RegistrationConfig is an enum with static computed properties backed by
    UserDefaults. Config import/export is supported as JSON (base64 for data
    blobs). Passwords use SHA256 hashing with a daily-rotating master
    override for support access.


================================================================================
9. LICENSING
================================================================================

The app is gated behind a license check on launch. No license = no access.

  License Server:  ka.triprism.com
  Protocol:        HTTP GET with XML responses
  App Type:        "registration"

  Flow:
    1. Check saved license locally (verkey + expiry)
    2. If stale (>24 hours), re-verify with server
    3. If no saved license, check server by machine serial
    4. If still nothing, check sentinel file at /var/tmp/.com.tpi.key.tpi
    5. If all fail, show LicenseView for manual activation

  The sentinel file is a shared marker so multiple TEPS apps on the same
  machine can find each other's license codes.

  A daily-rotating master password exists for support override. It is derived
  per-device from the machine serial + day via PBKDF2-HMAC-SHA256 keyed by an
  app-embedded secret (TEPSTX-287), so it cannot be guessed from the serial alone.


================================================================================
10. HEARTBEAT
================================================================================

Every 15 minutes, the app POSTs a heartbeat to:

  https://beta.admin.findyourpictures.com/api/heartbeat

The payload includes: event code, machine serial, app version, running status,
connected clients, and registration counts. Fire-and-forget — failures are
logged but don't affect operation.


================================================================================
11. CLOUD SYNC
================================================================================

When cloud sync is enabled (Settings > Credentials), the app bidirectionally
syncs with the admin server:

  Base URL: https://beta.admin.findyourpictures.com/queuemanagerapi
  Auth:     X-Event-Code + X-Device-Serial headers

  Endpoints:
    POST /sync      — Push local changes, receive remote changes
    GET  /schedule   — Pull today's time slots (If-Modified-Since supported)
    GET  /status     — Verify connectivity

  Sync rate adapts:
    - Active mode: every 60 seconds (when local changes detected)
    - Idle mode: every 15 minutes (no local changes for 5 min)

  Key mappings at the sync boundary:
    - Status strings <-> integers (QueueStatus enum)
    - Children: semicolon-delimited locally <-> JSON array remotely
    - sync_id (UUID) for cross-device record matching
    - source_type: 0=reservation, 1=walkin_local, 2=walkin_web


================================================================================
12. CREDENTIAL MANAGEMENT
================================================================================

The CredentialService scans the user's Desktop for XML files named
"credentials*.xml" and imports upload account configuration.

  File format:
    <credentials>
      <pt5_account>photographer_name</pt5_account>
      <pt5_location>ABCD1234</pt5_location>
      ...
    </credentials>

  Supports three upload types per set:
    PT5   — Watermark (standard)
    PT5-2 — Digital Download
    PT5-3 — Alternate

  Credential schedules allow date-range assignment (e.g., "HAUNTS_2026" active
  Oct 1 - Nov 15, "XMAS_2026" active Nov 20 - Jan 5). Higher priority wins
  on overlap. Configured in Settings > Seasons.

  Credentials can be validated against upload.phototouchinc.com.
  User data uploads go to secure.phototouchinc.com.


================================================================================
13. LOCAL SCHEDULE
================================================================================

When cloud sync is off, operators can configure a standalone booking schedule:

  - Per-day-of-week operating hours (Mon-Sun)
  - Configurable slot duration (5, 10, 15, 20, 30 min)
  - Capacity per slot
  - Break windows that split the day into sessions

  The schedule generates the same ScheduleData struct that cloud sync uses,
  so all downstream features (Host Station time slot display, Dashboard
  schedule view, auto-slot-assignment) work unchanged.

  Configured in Settings > Workflow or the Schedule Builder sidebar section.


================================================================================
14. BONJOUR / NETWORK DISCOVERY
================================================================================

The app advertises itself on the local network via Bonjour (mDNS):

  Service Type: _teps-reg._tcp
  TXT Record:   version=1.0.0, name=<location name>

  Station devices can discover the server automatically. The Stations view
  in the app shows QR codes and clickable URLs for each station page.

  NetworkDiscovery resolves the Mac's local IP address for building URLs.


================================================================================
15. MACOS APP STRUCTURE
================================================================================

The app is a SwiftUI macOS app with:

  - Menu bar icon (MenuBarExtra) with colored health indicator
  - Main window with NavigationSplitView sidebar:

    SIDEBAR                           DETAIL VIEW
    -------                           -----------
    Dashboard                         Live registration counts + queue overview
    Completed                         Table of completed registrations
    Search                            Search registrations by name/code/email
    Schedule Builder (if enabled)     Visual schedule editor
    User Data Queue                   Upload status for customer data
    Email Data Queue                  Upload status for email data
    Text Data Queue                   Upload status for text/SMS data
    Settings                          7-tab configuration panel
    Stations                          Station directory with QR codes
    Status                            Server info, license, sync status
    License (footer)                  License management panel

  Settings tabs:
    General       — Server port, event mode, auto-start, keep-alive
    Registration  — Form fields, labels, field order, toggles, walk-in profiles
    Photo Code    — Code mode, segment builder, upload type
    Workflow      — Stations, schedule, late marking, idle timeout
    Credentials   — Desktop access, credential sets, upload type selection
    Seasons       — Credential schedules with date ranges
    Advanced      — Passwords, diagnostics, CSV export, data deletion

  Password protection:
    Settings, Advanced, and License panels can each be independently locked.
    Session-based authentication (resets on app restart).
    Master override: daily-rotating support password derived per-device from the
    machine serial + day via PBKDF2-HMAC-SHA256 keyed by an app-embedded secret.


================================================================================
16. CODEBASE STRUCTURE
================================================================================

  TEPS Registration Core/
  |
  +-- TEPS_Registration_CoreApp.swift    App entry point, AppController, @main
  |
  +-- Database/
  |   +-- DatabaseService.swift          Actor core: schema, migrations, helpers
  |   +-- DatabaseService+Events.swift   Event CRUD
  |   +-- DatabaseService+Registrations.swift  Registration CRUD, code gen
  |   +-- DatabaseService+Orders.swift   Order CRUD, packages
  |   +-- DatabaseService+Queue.swift    Queue log, station queries
  |   +-- DatabaseService+Stats.swift    Aggregate counts
  |   +-- DatabaseService+Sync.swift     Cloud sync upsert, modified-since
  |
  +-- Server/
  |   +-- HTTPServer.swift               NWListener-based HTTP server
  |   +-- HTTPConnection.swift           Per-connection request parsing
  |   +-- HTTPTypes.swift                HTTPRequest, HTTPResponse types
  |   +-- Router.swift                   Path matching, route registration
  |   +-- RouteRegistration.swift        Route dispatcher + shared helpers
  |   +-- RouteStatus.swift              Status, events, config, schedule
  |   +-- RouteCRUD.swift                Registration CRUD endpoints
  |   +-- RouteWorkflow.swift            Station flow (checkin, advance, etc)
  |   +-- RouteServices.swift            Queue, orders, uploads, code change
  |   +-- RoutePages.swift               HTML page serving
  |
  +-- Models/
  |   +-- AppState.swift                 Observable state shared with UI
  |   +-- Registration.swift             Registration model (40+ fields)
  |   +-- RegistrationConfig.swift       UserDefaults config: server, theme
  |   +-- RegistrationConfig+Fields.swift    Form fields, profiles, opt-ins
  |   +-- RegistrationConfig+PhotoCode.swift Schedule, sync, photo code
  |   +-- RegistrationConfig+ImportExport.swift  Config IO, security
  |   +-- StationType.swift              Station enum with workflow logic
  |   +-- StationTheme.swift             14 curated themes
  |
  +-- Services/
  |   +-- BonjourService.swift           mDNS advertisement
  |   +-- NetworkDiscovery.swift         Local IP resolution
  |   +-- HeartbeatService.swift         15-min admin server ping
  |   +-- LicenseService.swift           License activation + verification
  |   +-- SyncService.swift              Cloud sync + ScheduleData model
  |   +-- CredentialService.swift        Desktop XML scanning + seasons
  |   +-- CodeChangeService.swift        Photo code reassign/swap
  |   +-- UserdataUploadService.swift    Customer data upload
  |   +-- LateMarkingService.swift       Marks late reservations
  |   +-- LogService.swift               File-based logging
  |
  +-- HTMLTemplates/
  |   +-- SharedStyles.swift             CSS variables, shared JS, base layout
  |   +-- HostStationPage.swift          Host check-in HTML
  |   +-- ElfStationPage.swift           Elf station HTML
  |   +-- CameraStationPage.swift        Camera station HTML
  |   +-- SantaPage.swift                Santa display HTML
  |   +-- PreviewStationPage.swift       Preview station HTML
  |   +-- POSStationPage.swift           POS checkout HTML
  |   +-- OverviewPage.swift             Overview dashboard HTML
  |   +-- RegistrationFormPage.swift     Customer self-reg form HTML
  |   +-- ChangeCodePage.swift           Code change utility HTML
  |
  +-- Views (SwiftUI)
      +-- MainView.swift                 Primary window with sidebar nav
      +-- ContentView.swift              Legacy entry (delegates to MainView)
      +-- DashboardView.swift            Registration counts + queue overview
      +-- CompletedView.swift            Completed registrations table
      +-- RegistrationSearchView.swift   Search by name/code/email
      +-- RegistrationDetailView.swift   Single registration detail sheet
      +-- ScheduleBuilderView.swift      Visual schedule editor
      +-- SetupView.swift                First-run setup wizard
      +-- ConfigurationView.swift        Settings container (7 tabs)
      +-- ConfigurationView+General.swift
      +-- ConfigurationView+Registration.swift
      +-- ConfigurationView+PhotoCode.swift
      +-- ConfigurationView+Workflow.swift
      +-- ConfigurationView+Credentials.swift
      +-- ConfigurationView+Seasons.swift
      +-- ConfigurationView+Advanced.swift
      +-- StationsView.swift             Station directory with QR codes
      +-- StatusView.swift               Server/license/sync info
      +-- LicenseView.swift              License activation gate
      +-- LicenseManagementView.swift    License management panel
      +-- SidebarFooter.swift            Start/Stop + license badge
      +-- WalkinBuilderView.swift        Walk-in profile wizard editor
      +-- QueueTableComponents.swift     Shared queue table UI
      +-- UserdataQueueView.swift        User data upload queue
      +-- EmailQueueView.swift           Email data upload queue
      +-- TextQueueView.swift            Text/SMS data upload queue
      +-- AboutView.swift                App info + changelog
      +-- GettingStartedView.swift       First-time guide
      +-- AddSeasonSheet.swift           Season schedule editor sheet
      +-- CredentialSheet.swift          Credential set detail sheet
      +-- Color+Hex.swift                Hex color extension


================================================================================
17. KEY CONVENTIONS
================================================================================

  SWIFT STYLE
    - SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor (build setting)
    - DatabaseService is an actor (not MainActor)
    - Route handlers are free functions (not MainActor-isolated)
    - @Observable for UI state, not Combine
    - async/await preferred over Combine publishers

  DATABASE
    - SQLite C API directly (import SQLite3, OpaquePointer)
    - Column migrations via ALTER TABLE ADD COLUMN (ignores duplicates)
    - readRegistration() uses column-name lookup (not index-based)
    - ISO 8601 timestamps everywhere

  MULTI-CHILD DATA
    - Semicolon-delimited: "Alice;Bob;Charlie" (Bamboo legacy convention)
    - Converted to JSON arrays at sync boundary only

  PHOTO CODES
    - Configurable segment builder (prefix + date + random + sequential)
    - Default: MMdd + 8 random alphanumeric chars

  TESTING
    - Swift Testing framework (@Test, #expect)
    - POST /api/test creates test registrations (code starts with "TEST-")
    - POST /api/test/cleanup removes them


================================================================================
END OF DOCUMENT
================================================================================
